﻿using NCS.IConnect.Core.Utilities;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Web;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Description;

namespace NCS.IConnect.Core.WebApi.Description
{
    /// <summary>
    /// Class CompositeXmlDocumentationProvider.
    /// </summary>
    public class CompositeXmlDocumentationProvider : IDocumentationProvider, IModelDocumentationProvider
    {
        private IEnumerable<XmlDocumentationProvider> documentationProviders;

        /// <summary>
        /// Initializes a new instance of the <see cref="CompositeXmlDocumentationProvider"/> class.
        /// </summary>
        /// <param name="controllerDescriptors">The controller descriptors.</param>
        /// <param name="path">The path.</param>
        public CompositeXmlDocumentationProvider(IEnumerable<HttpControllerDescriptor> controllerDescriptors, string path)
        {
            string[] assemblyNames = controllerDescriptors.Select(d => d.ControllerType.Assembly.GetName().Name).Distinct().ToArray();
            List<XmlDocumentationProvider> providers = new List<XmlDocumentationProvider>();
            foreach(string assemblyName in assemblyNames)
            {
                string fileName = HttpContext.Current.Server.MapPath(string.Format("{0}/{1}.xml", path, assemblyName));
                if(File.Exists(fileName))
                {
                    providers.Add(new XmlDocumentationProvider(fileName));
                }
            }
            this.documentationProviders = providers;
        }

        /// <summary>
        /// Gets the documentation based on <see cref="T:System.Web.Http.Controllers.HttpParameterDescriptor" />.
        /// </summary>
        /// <param name="parameterDescriptor">The parameter descriptor.</param>
        /// <returns>The documentation for the controller.</returns>
        [EnvironmentPermission(SecurityAction.LinkDemand, Unrestricted = true)]
        public string GetDocumentation(HttpParameterDescriptor parameterDescriptor)
        {
            return this.GetDocumentation(provider => provider.GetDocumentation(parameterDescriptor));
        }

        /// <summary>
        /// The documentation for a type member.
        /// </summary>
        /// <param name="member">The <see cref="MemberInfo" />.</param>
        /// <returns>The documentation for a type member.</returns>
        public string GetDocumentation(MemberInfo member)
        {
            return this.GetDocumentation(provider => provider.GetDocumentation(member));
        }

        /// <summary>
        /// Gets the documentation for a type.
        /// </summary>
        /// <param name="type">The <see cref="Type" />.</param>
        /// <returns>The documentation for a type.</returns>
        public string GetDocumentation(Type type)
        {
            return this.GetDocumentation(provider => provider.GetDocumentation(type));
        }

        /// <summary>
        /// Gets the documentation based on <see cref="T:System.Web.Http.Controllers.HttpActionDescriptor" />.
        /// </summary>
        /// <param name="actionDescriptor">The action descriptor.</param>
        /// <returns>The documentation for the controller.</returns>
        [EnvironmentPermission(SecurityAction.LinkDemand, Unrestricted = true)]
        public string GetDocumentation(HttpActionDescriptor actionDescriptor)
        {
            return this.GetDocumentation(provider => provider.GetDocumentation(actionDescriptor));
        }

        /// <summary>
        /// Gets the documentation.
        /// </summary>
        /// <param name="controllerDescriptor">The controller descriptor.</param>
        /// <returns>System.String.</returns>
        [EnvironmentPermission(SecurityAction.LinkDemand, Unrestricted = true)]
        public string GetDocumentation(HttpControllerDescriptor controllerDescriptor)
        {
            return this.GetDocumentation(provider => provider.GetDocumentation(controllerDescriptor));
        }

        /// <summary>
        /// Gets the response documentation.
        /// </summary>
        /// <param name="actionDescriptor">The action descriptor.</param>
        /// <returns>System.String.</returns>
        [EnvironmentPermission(SecurityAction.LinkDemand, Unrestricted = true)]
        public string GetResponseDocumentation(HttpActionDescriptor actionDescriptor)
        {
            return this.GetDocumentation(provider => provider.GetDocumentation(actionDescriptor));
        }

        private string GetDocumentation(Func<XmlDocumentationProvider, string> documentAccessor)
        {
            foreach (var provider in documentationProviders)
            {
                string documentation = documentAccessor(provider);
                if (!string.IsNullOrEmpty(documentation))
                {
                    return documentation;
                }
            }
            return null;
        }


        /// <summary>
        /// Gets the remark.
        /// </summary>
        /// <param name="member">The member.</param>
        /// <returns>System.String.</returns>
        public string GetRemark(MemberInfo member)
        {
            return this.GetDocumentation(provider => provider.GetRemark(member));
        }
    }
}